home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et-2_2.lha / et2.2 / src / CodeTextView.C < prev    next >
C/C++ Source or Header  |  1990-12-04  |  10KB  |  479 lines

  1. //$CodeTextView, CodeAnalyzer, PrettyPrinter$
  2.  
  3. #include "Port.h"
  4. #include "FixLineTView.h"
  5. #include "CodeTextView.h"
  6. #include "StyledText.h"
  7.  
  8. static char *match= "lass",
  9.         *obrackets = "({[\"",
  10.         *cbrackets = ")}]\"";
  11.  
  12. //---- CodeTextView ------------------------------------------------------------
  13.  
  14. MetaImpl(CodeTextView, (TB(autoIndent), T(cursorPos), 0));
  15.  
  16. CodeTextView::CodeTextView(EvtHandler *eh, Rectangle r, Text *t, eTextJust m, eSpacing sp, 
  17.                     TextViewFlags fl, Point b, int id)
  18.             : FixedLineTextView(eh, r, t, m, sp, FALSE, fl, b, id) 
  19. {
  20.     SetStopChars("\n\r");
  21.     autoIndent= TRUE;
  22.     SetupStyles(t->GetFont());
  23.     ExitCursorMode();
  24. }   
  25.  
  26. Command *CodeTextView::DoKeyCommand(int ch, Point lp, Token token)
  27. {
  28.     Command *cmd;
  29.  
  30.     ExitCursorMode();
  31.     if ((ch == '\r' || ch == '\n') && autoIndent) { // auto indent
  32.     int from, to, i;
  33.     Text *t= GetText();
  34.     GetSelection(&from,&to);
  35.     scratchText->Empty();
  36.     scratchText->Append('\n'); 
  37.     for (i= StartLine(CharToLine(from)); i < t->Size() ; i++) {
  38.         ch= (*t)[i];
  39.         if (ch == ' ' || ch == '\t')
  40.         scratchText->Append(ch);
  41.         else
  42.         break;
  43.     }
  44.     cmd= InsertText(scratchText);
  45.     scratchText->Empty();
  46.     RevealSelection();
  47.     return cmd;
  48.     }
  49.     return FixedLineTextView::DoKeyCommand(ch, lp, token);
  50. }
  51.  
  52. void CodeTextView::SetFont(Font *fp)
  53. {
  54.     SetupStyles(fp);
  55.     FixedLineTextView::SetFont(fp);
  56. }
  57.  
  58. void CodeTextView::SetupStyles(Font *fp)
  59. {
  60.     Font *fd1, *fd2, *fd3;
  61.     GrFont fid= fp->Fid();
  62.     int size= fp->Size();
  63.     fd1= new_Font(fid, size, eFacePlain);
  64.     fd2= new_Font(fid, size, eFaceItalic);
  65.     fd3= new_Font(fid, size, eFaceBold);
  66.  
  67.     commentStyle= new_Style(fd2);
  68.     functionStyle= new_Style(fd3);
  69.     classDeclStyle= new_Style(fd3);
  70.     plainStyle= new_Style(fd1);
  71. }
  72.  
  73. void CodeTextView::SetAutoIndent(bool b)
  74. {
  75.     autoIndent= b;
  76. }
  77.     
  78. bool CodeTextView::GetAutoIndent()
  79. {
  80.     return autoIndent;
  81. }
  82.  
  83. void CodeTextView::ExitCursorMode()
  84. {
  85.     cursorPos= gPoint_1;
  86. }
  87.  
  88. Command *CodeTextView::DoLeftButtonDownCommand(Point p, Token t, int cl)
  89. {
  90.     Point sp= p;
  91.     ExitCursorMode();
  92.     if (!Enabled())
  93.     return gNoChanges;
  94.     if (cl >= 2) {
  95.     int line, cpos;
  96.     char *br;
  97.     Point pp;
  98.     Text *text= GetText();
  99.  
  100.     p-= GetInnerOrigin();
  101.     PointToPos(p, &pp, &line, &cpos);
  102.     
  103.     if (cpos > 0 && (br= index(obrackets,(*text)[cpos-1]))) {
  104.         MatchBracketForward(cpos, *br, cbrackets[br-obrackets]);
  105.         return gNoChanges;
  106.     }
  107.     if (cpos < text->Size() && (br= index(cbrackets,(*text)[cpos]))) {
  108.         MatchBracketBackward(cpos-1, obrackets[br-cbrackets], *br);
  109.         return gNoChanges;
  110.     }
  111.     }
  112.     return FixedLineTextView::DoLeftButtonDownCommand(sp, t, cl);
  113. }
  114.  
  115. Command *CodeTextView::DoMenuCommand(int m)
  116. {
  117.     ExitCursorMode();
  118.     return TextView::DoMenuCommand(m);
  119. }
  120.     
  121. Command *CodeTextView::DoOtherEventCommand(Point p, Token t)
  122. {
  123.     ExitCursorMode();
  124.     return TextView::DoOtherEventCommand(p, t);
  125. }
  126.  
  127. void CodeTextView::MatchBracketForward(int from, int obracket, int cbracket)
  128. {
  129.     Text *text= GetText();
  130.     int ch, stack= 0;
  131.  
  132.     for (int i= from; i < text->Size(); i++) {
  133.     ch= (*text)[i];
  134.     if (ch == cbracket) {
  135.         if (stack-- == 0) 
  136.         break;
  137.     } else if (ch == obracket)
  138.         stack++;
  139.     }    
  140.     SetSelection(from, i, TRUE);
  141. }
  142.  
  143. void CodeTextView::MatchBracketBackward(int from, int obracket, int cbracket)
  144. {
  145.     Text *text= GetText();
  146.     int ch, stack= 0;
  147.  
  148.     for (int i= from; i >= 0; i--) {
  149.     ch= (*text)[i];
  150.     if (ch == obracket) { 
  151.         if (stack-- == 0) 
  152.         break;
  153.     } else if (ch == cbracket)
  154.         stack++;
  155.     }
  156.     SetSelection(i+1, from+1, TRUE);
  157. }
  158.  
  159. Command *CodeTextView::DoCursorKeyCommand(EvtCursorDir cd, Point p, Token t)
  160. {
  161.     switch (cd) {
  162.     case eCrsLeft:
  163.     case eCrsRight:
  164.     ExitCursorMode();
  165.     break;
  166.     default:
  167.     break;
  168.     }
  169.     return TextView::DoCursorKeyCommand(cd, p, t);
  170. }
  171.  
  172. int CodeTextView::CursorPos(int at, int line, EvtCursorDir d, Point p)
  173. {    
  174.     int charNo;
  175.     Point basePoint;
  176.     
  177.     if (cursorPos == gPoint_1) 
  178.     CharToPos (at,&line,&cursorPos);
  179.  
  180.     if (d == eCrsDown)
  181.     line= min(nLines-1, line+1);
  182.     else
  183.     line= max(0, line-1);        
  184.     basePoint= LineToPoint(line, TRUE) + Point(cursorPos.x, 0);
  185.     PointToPos(basePoint, &p, &line, &charNo);
  186.     return charNo;
  187. }
  188.  
  189. PrettyPrinter *CodeTextView::MakePrettyPrinter(Text *t, Style *cs, Style *fs,
  190.                             Style *cds, Style *ps)
  191. {
  192.     return new PrettyPrinter(t, cs, fs, cds, ps);
  193. }
  194.  
  195. void CodeTextView::FormatCode()
  196. {
  197.     if (!text->IsKindOf(StyledText)) 
  198.     return;
  199.     PrettyPrinter *pp= MakePrettyPrinter(text, commentStyle, functionStyle, classDeclStyle, plainStyle);
  200.     pp->Doit();
  201.     SafeDelete(pp);
  202. }
  203.  
  204. void CodeTextView::SetDefaultStyle()
  205. {
  206.     if (!text->IsKindOf(StyledText)) 
  207.     return;
  208.     StyledText *stext= (StyledText*)text;
  209.     TextRunArray *st= new TextRunArray(stext);
  210.     st->Insert(plainStyle, 0, 0, stext->Size());
  211.     TextRunArray *tmpp= stext->SetStyles(st);
  212.     delete tmpp;
  213. }
  214.  
  215. //---- CodeAnalyzer ----------------------------------------------------------
  216.  
  217. CodeAnalyzer::CodeAnalyzer(Text *t)
  218. {
  219.     text= t;
  220. }
  221.  
  222. void CodeAnalyzer::Doit()
  223. {
  224.     inDefine= escape= inClass= FALSE;
  225.     lastComment= prevCh= braceStack= inString= line= 0;
  226.     c= '\n'; 
  227.     int canBeClass= canBeFunction= -1;
  228.     AutoTextIter next(text, 0, text->Size());
  229.     Start();
  230.     
  231.     while ((c= next()) != cEOT) {
  232.     if (escape)
  233.         escape=FALSE;
  234.     else
  235.         switch (c) {
  236.         case '#':
  237.         if (prevCh == '\n')
  238.             inDefine= TRUE;
  239.         break;
  240.         case '\\':
  241.         escape= TRUE;
  242.         break;
  243.         case '\n':
  244.         inDefine= FALSE;
  245.         line++;
  246.         break;
  247.         case '*':
  248.         if (prevCh == '/' && inString == 0) {
  249.             if (canBeFunction == -1 && canBeClass == -1)
  250.             lastComment= next.GetPos(); 
  251.             FoundComment(&next);
  252.             prevCh= 0;
  253.             continue;
  254.         }
  255.         break;
  256.         case '/':
  257.         if (prevCh == '/' && inString == 0) {
  258.             if (canBeFunction == -1 && canBeClass == -1)
  259.             lastComment= next.GetPos(); 
  260.             FoundEndOfLineComment(&next);
  261.             prevCh= 0;
  262.             continue;
  263.         }
  264.         break;
  265.         case ';':
  266.         canBeFunction= canBeClass= -1;
  267.         break;
  268.         case '{':
  269.         if (canBeFunction != -1) {
  270.             FoundFunctionOrMethod(canBeFunction, lastComment);
  271.             canBeFunction= -1;
  272.         }
  273.         if (canBeClass != -1) {
  274.             FoundClassDecl(canBeClass);
  275.             canBeClass= -1;
  276.         }
  277.         if (inString == 0)
  278.             braceStack++;
  279.         break;
  280.         case '}':
  281.         if (inString == 0)
  282.             braceStack--;
  283.         break;
  284.         case '(':
  285.         if (!inDefine && inString == 0) {
  286.             if (braceStack == 0 && canBeFunction == -1)
  287.             canBeFunction= next.GetPos()-1;
  288.             braceStack++;
  289.         }
  290.         break;
  291.         case ')':
  292.         if (!inDefine && inString == 0)
  293.             braceStack--;
  294.         break;
  295.         case '\'':
  296.         case '\"':
  297.         if (inString == 0) {
  298.             if (c == '\"')
  299.             inString= '\"';
  300.             else
  301.             inString= '\'';
  302.         } else {
  303.             if ((inString == '\"' && c == '\"') || (inString == '\'' 
  304.                              && c == '\''))
  305.             inString= 0;
  306.         }
  307.         break;
  308.         default:
  309.         if (c == 'c' && !inDefine && inString == 0 
  310.             && !inClass && canBeClass == -1) {
  311.             if (braceStack == 0)
  312.             if (inClass= IsClassDecl(next.GetPos()))
  313.                 next.SetPos(next.GetPos()+4);
  314.         } else if (inClass && Isinword(c)) {
  315.             inClass= FALSE;
  316.             canBeClass= next.GetPos();
  317.         }
  318.         break;
  319.     }
  320.     prevCh= c;
  321.     }
  322.     
  323.     End();
  324. }
  325.  
  326. void CodeAnalyzer::FoundComment(AutoTextIter *next)
  327. {
  328.     int start= next->GetPos()-2;
  329.     int end, c, prevCh= 0, l= line;
  330.    
  331.     while ((c= (*next)()) != cEOT) {
  332.     if (c == '\n')
  333.         line++;
  334.     if (c == '/' && prevCh == '*') {
  335.         end= next->GetPos();
  336.         Comment(l, start, end);
  337.         break;
  338.     }
  339.     prevCh= c;
  340.     }
  341. }
  342.  
  343. void CodeAnalyzer::FoundEndOfLineComment(AutoTextIter *next)
  344. {
  345.     int start= next->GetPos()-2;
  346.     int end, c;
  347.  
  348.     while ((c= (*next)()) != cEOT) 
  349.     if (c == '\n') {
  350.         end= next->GetPos()-1;
  351.         Comment(line, start, end);
  352.         line++;
  353.         break;
  354.     }
  355. }
  356.  
  357. void CodeAnalyzer::FoundFunctionOrMethod(int at, int lastComment)
  358. {
  359.     byte c;
  360.     int pos= at, len= 0;
  361.     while (--pos >= lastComment) {
  362.     c= (*text)[pos];
  363.     if (!Isspace(c) && !index("[]*+-=%&><|:^%()~/",c)) // overloaded operators
  364.         break;
  365.     }
  366.     while (pos >= lastComment) {
  367.     c= (*text)[pos];
  368.     if (!(Isinword(c) || c == ':' || c == '~' ))
  369.         break;
  370.     if (pos-1 < 0)
  371.         break;
  372.     pos--;
  373.     len++;
  374.     }
  375.     
  376.     if (len) {
  377.     char buf[500];
  378.     pos++;
  379.     text->CopyInStr((byte*)buf, sizeof buf, pos, pos+len);
  380.     char *p= index(buf, ':');
  381.     if (!p)
  382.         Function(line, pos, pos+len, buf, 0);
  383.     else {
  384.         *p= '\0';
  385.         char *pp= p+2;
  386.         Function(line, pos, pos+len, pp, buf);
  387.     }
  388.     }
  389. }
  390.  
  391. bool CodeAnalyzer::IsClassDecl(int at)
  392. {
  393.     char *p= match;
  394.     int c;
  395.     AutoTextIter next(text, at, text->Size());
  396.     while ((c= next()) != cEOT && *p) {
  397.     if (c != *p++) 
  398.         return FALSE;
  399.     }
  400.     return TRUE;
  401. }
  402.  
  403. void CodeAnalyzer::FoundClassDecl(int at)
  404. {
  405.     int start= at-1;
  406.     AutoTextIter next(text, start, text->Size());
  407.     int end, c;
  408.  
  409.     while ((c= next()) != cEOT) 
  410.     if (!Isinword(c)) 
  411.         break;
  412.     end= next.GetPos()-1;
  413.     if (start != end) {
  414.     static byte name[1000];
  415.     text->CopyInStr(name, sizeof name, start, end);
  416.     ClassDecl(line, start, end, (char*)name);
  417.     }
  418. }
  419.  
  420. void CodeAnalyzer::Start()
  421. {
  422. }
  423.  
  424. void CodeAnalyzer::End()
  425. {
  426. }
  427.  
  428. void CodeAnalyzer::Comment(int, int, int)
  429. {
  430. }
  431.  
  432. void CodeAnalyzer::ClassDecl(int, int, int, char *)
  433. {
  434. }
  435.     
  436. void CodeAnalyzer::Function(int, int, int, char *, char *)
  437. {
  438. }
  439.  
  440. //---- PrettyPrinter ---------------------------------------------------------
  441.  
  442. PrettyPrinter::PrettyPrinter(Text *t, Style *cs, Style *fs, Style *cds,
  443.                     Style *ps) : CodeAnalyzer(t)
  444. {
  445.     stext= Guard(t, StyledText);
  446.     plainStyle= ps;
  447.     commentStyle= cs;
  448.     classDeclStyle= cds;
  449.     functionStyle= fs;
  450. }
  451.  
  452. void PrettyPrinter::Start()
  453. {
  454.     st= new TextRunArray(stext);
  455.     st->Insert(plainStyle, 0, 0, stext->Size());
  456. }
  457.  
  458. void PrettyPrinter::End()
  459. {
  460.     TextRunArray *tmpp= stext->SetStyles(st);
  461.     delete tmpp;
  462. }
  463.  
  464. void PrettyPrinter::Comment(int, int start, int end)
  465. {
  466.     st->Insert(commentStyle, start, end, end-start);
  467. }
  468.  
  469. void PrettyPrinter::ClassDecl(int, int start, int end, char *)
  470. {
  471.     st->Insert(classDeclStyle, start, end, end-start);
  472. }
  473.     
  474. void PrettyPrinter::Function(int, int start, int end, char *, char *)
  475. {
  476.     st->Insert(functionStyle, start, end, end-start);
  477. }
  478.  
  479.